use std::mem::swap;

pub const M_PI: f32 = std::f32::consts::PI;

pub const K_INFINITY: f32 = f32::MAX;

pub fn clamp(lo: f32, hi: f32, v: f32) -> f32 {
    lo.max(hi.min(v))
}

pub fn solve_quadratic(a: f32, b: f32, c: f32, x0: &mut f32, x1: &mut f32) -> bool {
    let discr = b * b - 4.0 * a * c;
    if discr < 0. {
        false
    } else if discr == 0. {
        *x0 = -0.5 * b / a;
        *x1 = -0.5 * b / a;
        true
    } else {
        let q = if b > 0. {
            -0.5 * (b + discr.sqrt())
        } else {
            -0.5 * (b - discr.sqrt())
        };
        *x0 = q / a;
        *x1 = c / q;
        if x0 > x1 {
            swap(x0, x1);
        }
        true
    }
}

#[derive(Clone, Copy)]
pub enum MaterialType {
    DiffuseAndGlossy,
    ReflectionAndRefraction,
    Reflection,
}

pub fn get_random_float() -> f32 {
    rand::random::<f32>()
}

pub fn update_progress(progress: f32) -> () {
    let bar_width = 100;
    let pos = (bar_width as f32 * progress) as i32;
    for i in 0..bar_width {
        if i < pos {
            print!("=");
        } else if i == pos {
            print!(">");
        } else {
            print!(" ")
        }
    }
    print!("] {}%\r", pos);
}

#[cfg(test)]
mod test {
    use super::update_progress;

    #[test]
    fn test_progress_bar() {
        let a = vec![0.02, 0.05, 0.2, 0.5, 0.7, 0.89, 0.99, 1.];
        for i in a {
            std::thread::sleep(std::time::Duration::from_millis(200));
            update_progress(i);
        }
    }
}
